Server.php
<?php
namespace Tlf\Tester;
/**
* convenience methods for server-related tests
* Server-related assertions may go here too
*
* @todo stop using file_get_contents() so I check for redirects & stuff
*/
trait Server {
/**
*
* @param $server the server name
* @return a string like `http://localhost:3000`
*/
public function get_server(string $server='main'){
$host = $this->cli->get_server_host($server);
return $host;
}
/**
*
* @param $path the path component of a url
* @param $params an array of paramaters to pass in the url
*
* @note $path cannot contain query string if params are passed
* @warning this early implementation will change
*
* @usage $response_content = $this->get('/', ['cat'=>'Jefurry']);
*/
public function get($path, $params=[], $server='main'){
$host = $this->cli->get_server_host($server);
$url = $host.$path;
if ($params!=[]) $url .= '?' . http_build_query($params);
$ch = curl_init();
curl_setopt_array($ch,
[
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => false,
// CURLOPT_POSTFIELDS => http_build_query($params),
// CURLOPT_POSTFIELDS => $params,
CURLOPT_FOLLOWLOCATION => true,
]
);
$output = curl_exec($ch);
curl_close($ch);
return $output;
}
/**
*
* @param $path the path component of a url
* @param $params an array of paramaters to pass via $_POST
* @param $files key=>value array of files where key = short file name & value = local file path
*
* @note $params['key'] will be overwritten by $files['key'] for the upload
* @note(jan 4, 2022) follows redirects ('Location:' header)
*
* @note $path cannot contain query string if params are passed
*
* @usage $response_content = $this->get('/', ['cat'=>'Jefurry']);
*/
public function post($path, $params=[], $files=[], $server='main'){
$host = $this->cli->get_server_host($server);
$url = $host.$path;
$ch = curl_init();
$this->curl_add_files($ch, $files, $params);
curl_setopt_array($ch,
[
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
// CURLOPT_POSTFIELDS => http_build_query($params),
CURLOPT_POSTFIELDS => $params,
CURLOPT_FOLLOWLOCATION => true,
// CURLOPT_HEADER=>true,
// CURLINFO_HEADER_OUT=>true,
]
);
$output = curl_exec($ch);
curl_close($ch);
return $output;
}
/**
*
* @beta
*
* @param $headers array like `['HeaderKey: header_value', 'Cookie'=> 'cookie_key=cookie_value;cookie2=value2;']` ... ONLY `Cookie` should have an array key. All other header keys should be in the array value and use a numeric index
* @return array with keys header_text, body, headers, cookies
*/
public function curl_post($path, $params=[], $files=[], $server='main', $headers=[]){
$ch = curl_init();
$host = $this->cli->get_server_host();
$url = $host.$path;
// echo 'zip zap';
//
// print_r($headers);
// exit;
if (isset($headers['Cookie'])){
// var_dump($headers);
// exit;
$cookie = $headers['Cookie'];
unset($headers['Cookie']);
curl_setopt($ch, CURLOPT_COOKIE, $cookie);
}
curl_setopt_array($ch,
[
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
// CURLOPT_POSTFIELDS => http_build_query($params),
CURLOPT_POSTFIELDS => $params,
CURLOPT_HEADER => true,
CURLOPT_FOLLOWLOCATION => false,
CURLOPT_HTTPHEADER => $headers,
]
);
$response = curl_exec($ch);
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
curl_close($ch);
$header_text = substr($response,0,$header_size);
$parts = explode("\n", $header_text);
$parts = array_map('trim', $parts);
$headers = [];
$cookies = [];
foreach ($parts as $line){
$pos = strpos($line,':');
if ($pos===false)continue;
$key = substr($line,0,$pos);
$value = trim(substr($line,$pos+1));
if (isset($headers[$key])){
if (!is_array($headers[$key]))$headers[$key] = [$headers[$key]];
$headers[$key][] = $value;
} else {
$headers[$key] = $value;
}
if ($key=='Set-Cookie'){
$cookie = $this->parse_cookie_header($value);
$cookies[$cookie['name']] = $cookie;
}
}
// TODO: parse Set-Cookie headers
$body = substr($response,$header_size);
return [
'header_text'=>$header_text,
'body'=>$body,
'headers'=>$headers,
'cookies'=>$cookies,
];
}
/**
*
* @beta(may 4, 2022)
*
* @see curl_post(). It is the same except no `$files` param here
*/
public function curl_get($path, $params=[], $server='main', $headers=[]){
$ch = curl_init();
$host = $this->cli->get_server_host();
$url = $host.$path;
if ($params!=[]) $url .= '?' . http_build_query($params);
// echo 'zip zap';
//
// print_r($headers);
// exit;
if (isset($headers['Cookie'])){
// var_dump($headers);
// exit;
$cookie = $headers['Cookie'];
unset($headers['Cookie']);
curl_setopt($ch, CURLOPT_COOKIE, $cookie);
}
curl_setopt_array($ch,
[
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => false,
// CURLOPT_POSTFIELDS => http_build_query($params),
// CURLOPT_POSTFIELDS => $params,
CURLOPT_HEADER => true,
CURLOPT_FOLLOWLOCATION => false,
CURLOPT_HTTPHEADER => $headers,
]
);
$response = curl_exec($ch);
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
curl_close($ch);
$header_text = substr($response,0,$header_size);
$parts = explode("\n", $header_text);
$parts = array_map('trim', $parts);
$headers = [];
$cookies = [];
foreach ($parts as $line){
$pos = strpos($line,':');
if ($pos===false)continue;
$key = substr($line,0,$pos);
$value = trim(substr($line,$pos+1));
if (isset($headers[$key])){
if (!is_array($headers[$key]))$headers[$key] = [$headers[$key]];
$headers[$key][] = $value;
} else {
$headers[$key] = $value;
}
if ($key=='Set-Cookie'){
$cookie = $this->parse_cookie_header($value);
$cookies[$cookie['name']] = $cookie;
}
}
// TODO: parse Set-Cookie headers
$body = substr($response,$header_size);
return [
'header_text'=>$header_text,
'body'=>$body,
'headers'=>$headers,
'cookies'=>$cookies,
];
}
/**
* @param $header_value, for `Set-cookie: whatever whatever`, this should be `whatever whatever`
* @return array parsed cookie
*
*
* @issue has no handling for a cookie value containing a semi-colon or an equal sign
*/
public function parse_cookie_header($header_value): array {
$cookie = [];
$parts = explode(';', $header_value);
$parts = array_map('trim',$parts);
$main = array_shift($parts);
$main_parts = explode('=', $main);
$cookie['name'] = $main_parts[0];
$cookie['value'] = $main_parts[1];
foreach ($parts as $str){
$kv_parts = explode('=', $str);
if (count($kv_parts)==1)$cookie[$str] = true;
else $cookie[$kv_parts[0]] = $kv_parts[1];
}
return $cookie;
}
/**
* @param $ch curl handle
* @param $files array of key=>absolute file paths
* @param $params array to use as CURLOPT_POSTFIELDS
*/
public function curl_add_files($ch, array $files, array &$params){
foreach ($files as $name=>$path){
$mimetype = mime_content_type($path);
// $mimetype = false;
if ($mimetype==false){
$ext = pathinfo($path,PATHINFO_EXTENSION);
$list = require(dirname(__DIR__).'/mime_type_map.php');
$mimetype = $list['mimes'][$ext][0];
}
$params[$name] = new \CURLFile($path, $mimetype, basename($path));
}
}
}